package com.frank.loadinglibrary.common;

import ohos.agp.components.AttrSet;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;

import java.util.ArrayList;

/**
 * @author : frank
 * @date : 2021/4/29 15:36
 */
public class StripLoadingComponent extends BaseLoadingComponent {

    private float stripPercent = 0.3f;

    private Paint mPaint = new Paint();

    private Paint shadowPaint = new Paint();

    private float radius = 20f;

    private int stripeWidth;

    private int intervalWidth;

    private ArrayList<Point> pointArrayList = new ArrayList<>();

    private boolean isInitialized = false;

    private String backgroundColor = "#ffffff";

    private String stripeColor = "#338FE8";

    private String shadowColor = "#ffffff";

    private int frame = 40;

    private int pixelPerFrame = 3;


    public StripLoadingComponent setBackgroundColor(String backgroundColor) {
        this.backgroundColor = backgroundColor;
        return this;
    }

    public StripLoadingComponent setStripeColor(String stripeColor) {
        this.stripeColor = stripeColor;
        return this;
    }

    public StripLoadingComponent setStripeWidth(int stripeWidth) {
        this.stripeWidth = stripeWidth;
        return this;
    }

    public StripLoadingComponent setIntervalWidth(int intervalWidth) {
        this.intervalWidth = intervalWidth;
        return this;
    }

    public StripLoadingComponent setRadius(float radius) {
        this.radius = radius;
        return this;
    }

    public StripLoadingComponent setAutoStart(boolean autoStart) {
        super.setAutoStart(autoStart);
        this.autoStart = autoStart;
        return this;
    }

    public void setFrame(int frame) {
        this.frame = frame;
    }

    public void setPixelPerFrame(int pixelPerFrame) {
        this.pixelPerFrame = pixelPerFrame;
    }

    private EventHandler animationHandler = new EventHandler(EventRunner.getMainEventRunner()) {

        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            getContext().getUITaskDispatcher().delayDispatch(() ->
                    sendEvent(1), 1000 / frame);

            invalidate();
        }
    };

    public StripLoadingComponent(Context context) {
        this(context, null);
    }

    public StripLoadingComponent(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public StripLoadingComponent(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initUI();
    }

    private void initUI() {
        DrawTask task = (component, canvas) -> {
            setPaint();
            draw(canvas, mPaint);
        };
        addDrawTask(task);
    }

    private void draw(Canvas canvas, Paint mPaint) {
        int width = getWidth();
        int height = getHeight();


        float loadingTop = (1 - stripPercent) * height / 2f;
        float loadingBottom = (1 + stripPercent) * height / 2f;

        RectFloat outerRect = new RectFloat(0, loadingTop, width, loadingBottom);
        canvas.drawRoundRect(outerRect, radius, radius, shadowPaint);

        RectFloat rectFloat = new RectFloat(0, loadingTop, width, loadingBottom);
        canvas.drawRoundRect(rectFloat, radius, radius, mPaint);

        stripeWidth = width / 10;
        intervalWidth = width / 10;

        int count = width / (stripeWidth + intervalWidth) + 2;

        if (!isInitialized) {
            for (int i = 0; i < count; i++) {
                Point point = new Point();
                point.position[0] = (-1 + i) * (stripeWidth + intervalWidth);
                pointArrayList.add(point);
            }
            isInitialized = true;
        } else {
            if (pointArrayList.get(pointArrayList.size() - 1).getPointX() > width) {
                pointArrayList.get(pointArrayList.size() - 1).position[0] = -stripeWidth - intervalWidth;
                pointArrayList.add(0, pointArrayList.get(pointArrayList.size() - 1));
                pointArrayList.remove(pointArrayList.size() - 1);
            }
            for (int i = 0; i < count; i++) {
                pointArrayList.get(i).position[0] = pointArrayList.get(i).position[0] + pixelPerFrame;
            }
        }

        for (int i = 0; i < count; i++) {
            Path path = new Path();
            canvas.save();
            path.reset();
            float topStartX = pointArrayList.get(i).getPointX();
            float bottomStartX = topStartX + intervalWidth;

            path.moveTo(pointArrayList.get(i).getPointX(), rectFloat.top);
            Point leftCenterPoint = new Point((topStartX + bottomStartX) / 2, (rectFloat.top + rectFloat.bottom) / 2);
            path.quadTo(new Point((bottomStartX + 3 * topStartX) / 4f + 7, (rectFloat.bottom + 3 * rectFloat.top) / 4f), leftCenterPoint);
            path.quadTo(new Point((3 * bottomStartX + topStartX) / 4f - 7, (3 * rectFloat.bottom + rectFloat.top) / 4f), new Point(bottomStartX, rectFloat.bottom));
            path.lineTo(bottomStartX + stripeWidth, rectFloat.bottom);
            Point rightCenterPoint = new Point((topStartX + bottomStartX + 2 * stripeWidth) / 2, (rectFloat.top + rectFloat.bottom) / 2);
            path.quadTo(new Point((3 * (bottomStartX + stripeWidth) + topStartX + stripeWidth) / 4f - 7, (3 * rectFloat.bottom + rectFloat.top) / 4f), rightCenterPoint);
            path.quadTo(new Point((bottomStartX + stripeWidth + 3 * (topStartX + stripeWidth)) / 4f + 7, (rectFloat.bottom + 3 * rectFloat.top) / 4f), new Point(topStartX + stripeWidth, rectFloat.top));
            canvas.clipPath(path, Canvas.ClipOp.INTERSECT);
            canvas.drawColor(Color.getIntColor(stripeColor), BlendMode.SRC);
            canvas.restore();
        }

        if (autoStart) {
            startAnimators();
        }
    }

    private void setPaint() {
        mPaint.setColor(new Color(Color.getIntColor(backgroundColor)));
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);

        shadowPaint.setColor(new Color(Color.getIntColor(shadowColor)));
        MaskFilter maskFilter = new MaskFilter(15
                , MaskFilter.Blur.OUTER);
        shadowPaint.setMaskFilter(maskFilter);
    }


    @Override
    protected void stopAnimators() {
        animationHandler.removeAllEvent();
    }

    @Override
    protected void startAnimators() {
        animationHandler.sendEvent(1);
    }

    @Override
    protected void releaseSource() {

    }
}
